@extend %card;
padding: 0 !important;
- // icon container
- .message-icon-bin {
- padding: ($base_padding * 3);
-
- &:ltr {padding-right:$base_padding;}
- &:rtl {padding-left:$base_padding;}
+ // subtract side padding to accommodate the close button
+ &:ltr { padding-right: $base_padding - 2px; };
+ &:rtl { padding-left: $base_padding - 2px; };
+
+ // message header
+ .message-header {
+ padding: 0 $scaled_padding;
+ margin: 0 $base_padding;
+ margin-top: $base_padding;
+ color: $insensitive_fg_color;
+ spacing: $base_padding;
- // icon size and color
- > StIcon {
- icon-size: $large_icon_size;
+ // header source icon
+ .message-source-icon {
+ padding: 2px 0;
+ icon-size: $scalable_icon_size; // 16px
-st-icon-style: symbolic;
}
- }
- // content
- .message-content {
- spacing: 4px;
- padding: ($base_padding * 1.5);
- margin-bottom: $base_margin * 2;
+ // box that contains the source icon, source name and timestamp of the message
+ .message-header-content {
+ spacing: $base_padding;
+ min-height: to_em(24px);
+ padding-bottom: $base_padding;
+
+ // header source title
+ .message-source-title {
+ font-weight: bold;
+ }
+
+ // Time label
+ .event-time {
+ @extend %caption;
+ color: $insensitive_fg_color;
+ // Add bottom padding to align the app name with the time horizontally
+ padding-bottom: to_em(1px);
+
+ &:ltr { text-align: right };
+ &:rtl { text-align: left };
+ }
+ }
+
+ // close button
+ .message-close-button {
+ @extend .icon-button;
+ color: $fg_color !important;
+ background-color: transparentize($fg_color, 0.8);
+ padding: 0 !important;
+ border: 4px transparent solid;
+ &:hover {background-color: transparentize($fg_color, 0.7);}
+ &:insensitive {background-color: transparentize($fg_color, 0.9);}
+ &:active {background-color: transparentize($fg_color, 0.8);}
+ }
}
- .message-title-box {
+ // container for message contents
+ .message-box {
+ padding: 0 $base_padding;
+ padding-bottom: $base_padding;
+ margin: $base_padding;
+ margin-top: $base_padding;
spacing: $base_padding;
- // title
- .message-title {
- font-weight: bold;
- }
- // notification time stamp
- > .event-time {
- @extend %caption;
- color: $insensitive_fg_color;
- padding-bottom: to_em(1px);
+ // icon container
+ .message-icon-bin {
+ &:ltr {padding-right:$base_padding;}
+ &:rtl {padding-left:$base_padding;}
- &:ltr { text-align: right };
- &:rtl { text-align: left };
+ // icon size and color
+ > StIcon {
+ icon-size: $base_icon_size * 3; // 48px
+ -st-icon-style: symbolic;
+ }
}
- }
+ // If the header isn't displayed we need more top margin
+ &:first-child {
+ margin-top: $base_padding * 2;
+ }
- // close button
- .message-close-button {
- @extend .icon-button;
- color: $fg_color;
- background-color: transparentize($fg_color, 0.8);
- padding: 0 !important;
- border: 5px transparent solid;
- margin: 1px;
- &:hover {background-color: transparentize($fg_color, 0.7);}
- &:active {background-color: transparentize($fg_color, 0.8);}
- }
+ // text of the message
+ .message-content {
+ spacing: $base_margin;
- // body
- .message-body {color: darken($fg_color, 10%);}
+ // message title
+ .message-title {
+ font-weight: bold;
+ }
+ }
+ }
}
// URLs in messages
/* Media Controls */
.message-media-control {
padding: 0 $base_padding * 3;
- margin: $base_padding * 2 0;
border-radius: $base_border_radius;
color: $fg_color;
border: 1px solid transparent;
}
}
- // fix margin for last button
- &:last-child:ltr { margin-right: $base_margin * 3; }
- &:last-child:rtl { margin-left: $base_margin * 3; }
-
& StIcon { icon-size: $base_icon_size; }
}
}
});
+const MessageHeader = GObject.registerClass(
+class MessageHeader extends St.BoxLayout {
+ constructor(source) {
+ super({
+ style_class: 'message-header',
+ x_expand: true,
+ });
+
+ const sourceIconEffect = new Clutter.DesaturateEffect();
+ const sourceIcon = new St.Icon({
+ style_class: 'message-source-icon',
+ y_align: Clutter.ActorAlign.CENTER,
+ fallback_icon_name: 'application-x-executable-symbolic',
+ });
+ sourceIcon.add_effect(sourceIconEffect);
+ this.add_child(sourceIcon);
+
+ sourceIcon.connect('style-changed', () => {
+ const themeNode = sourceIcon.get_theme_node();
+ sourceIconEffect.enabled = themeNode.get_icon_style() === St.IconStyle.SYMBOLIC;
+ });
+
+ const headerContent = new St.BoxLayout({
+ style_class: 'message-header-content',
+ y_align: Clutter.ActorAlign.CENTER,
+ x_expand: true,
+ });
+ this.add_child(headerContent);
+
+ this.closeButton = new St.Button({
+ style_class: 'message-close-button',
+ icon_name: 'window-close-symbolic',
+ y_align: Clutter.ActorAlign.CENTER,
+ opacity: 0,
+ });
+ this.add_child(this.closeButton);
+
+ const sourceTitle = new St.Label({
+ style_class: 'message-source-title',
+ y_align: Clutter.ActorAlign.END,
+ });
+ headerContent.add_child(sourceTitle);
+
+ source.bind_property_full('title',
+ sourceTitle,
+ 'text',
+ GObject.BindingFlags.SYNC_CREATE,
+ // Translators: this is the string displayed in the header when a message
+ // source doesn't have a name
+ (bind, value) => [true, value === null || value === '' ? _('Unknown App') : value],
+ null);
+ source.bind_property('icon',
+ sourceIcon,
+ 'gicon',
+ GObject.BindingFlags.SYNC_CREATE);
+
+ this.timeLabel = new TimeLabel();
+ headerContent.add_child(this.timeLabel);
+ }
+});
+
export const Message = GObject.registerClass({
Signals: {
'close': {},
'unexpanded': {},
},
}, class Message extends St.Button {
- _init(title, body) {
+ _init(source, title, body) {
super._init({
style_class: 'message',
accessible_role: Atk.Role.NOTIFICATION,
});
this.set_child(vbox);
- let hbox = new St.BoxLayout();
+ this._header = new MessageHeader(source);
+ vbox.add_child(this._header);
+
+ const hbox = new St.BoxLayout({
+ style_class: 'message-box',
+ });
vbox.add_child(hbox);
this._actionBin = new St.Widget({
this._mediaControls = new St.BoxLayout();
hbox.add_child(this._mediaControls);
- let titleBox = new St.BoxLayout({style_class: 'message-title-box'});
- contentBox.add_child(titleBox);
-
this.titleLabel = new St.Label({
style_class: 'message-title',
y_align: Clutter.ActorAlign.END,
});
this.setTitle(title);
- titleBox.add_child(this.titleLabel);
-
- this._timeLabel = new TimeLabel();
- titleBox.add_child(this._timeLabel);
-
- this._closeButton = new St.Button({
- style_class: 'message-close-button',
- icon_name: 'window-close-symbolic',
- y_align: Clutter.ActorAlign.CENTER,
- opacity: 0,
- });
- titleBox.add_child(this._closeButton);
+ contentBox.add_child(this.titleLabel);
this._bodyStack = new St.Widget({x_expand: true});
this._bodyStack.layout_manager = new LabelExpanderLayout();
this._bodyStack.add_child(this.bodyLabel);
this.setBody(body);
- this._closeButton.connect('clicked', this.close.bind(this));
- let actorHoverId = this.connect('notify::hover', this._sync.bind(this));
- this._closeButton.connect('destroy', this.disconnect.bind(this, actorHoverId));
this.connect('destroy', this._onDestroy.bind(this));
+
+ this._header.closeButton.connect('clicked', this.close.bind(this));
+ let actorHoverId = this.connect('notify::hover', this._sync.bind(this));
+ this._header.closeButton.connect('destroy', this.disconnect.bind(this, actorHoverId));
this._sync();
}
}
get datetime() {
- return this._timeLabel.datetime;
+ return this._header.timeLabel.datetime;
}
set datetime(datetime) {
- this._timeLabel.datetime = datetime;
+ this._header.timeLabel.datetime = datetime;
}
setTitle(text) {
_sync() {
let visible = this.hover && this.canClose();
- this._closeButton.opacity = visible ? 255 : 0;
- this._closeButton.reactive = visible;
+ this._header.closeButton.opacity = visible ? 255 : 0;
+ this._header.closeButton.reactive = visible;
}
_onDestroy() {